﻿using System;
using UnityEngine;
using UnityEngine.UI;

/// <summary>
/// 技能管理器，该对象是单例，使用静态属性 <see cref="Instance"/> 获取到实例对象。
/// 使用时，将该组件挂载在一个空 <c>GameObject</c> 中。
/// 另外需要注意，该类的单例是由 <see cref="Awake"/> 方法创建，所以其他类中使用该单例对象时，需要避免在 <c>Awake</c> 中调用，可以在 <c>OnEnable</c> 或 <c>Start</c> 中使用。
/// </summary>
public class SkillManager : MonoBehaviour
{
    public GameObject skillButtonParent;    // 技能按钮的父级

    [Header("技能显示板")]
    public Text skillPointText;
    public Image skillImage;
    public Text skillNameText;
    public Text skillLevelText;
    public Text skillDesText;

    [Header("技能点")]
    public int skillPoints;     // 可用的技能点数
    public int maxSkillPoints = 20;     // 最大的技能点数


    /// <summary>
    /// 选中技能后触发的事件
    /// </summary>
    public event Action<SkillData> SkillSelectedEvent;
    /// <summary>
    /// 升级技能后触发的事件
    /// </summary>
    public event Action<SkillData> UpgradeSkillEvent;


    private SkillData selectedSkill;        // 选中的技能
    private SkillButton[] skillButtons;     // 所有的skillButton


    /// <summary>
    /// <see cref="SkillManager"/> 实例
    /// </summary>
    public static SkillManager Instance
    {
        get;
        private set;
    }


    private void Awake()
    {
        if (Instance != null)
        {
            Destroy(gameObject);
            return;
        }
        Instance = this;

        skillButtons = skillButtonParent.GetComponentsInChildren<SkillButton>(true);

        DontDestroyOnLoad(gameObject);
    }


    private void OnGUI()
    {
        skillPointText.text = $"{skillPoints}/{maxSkillPoints}";
    }


    #region 对外可用功能
    /// <summary>
    /// 设置选中的技能
    /// </summary>
    public SkillData SelectedSkill
    {
        get => selectedSkill;
        set
        {
            selectedSkill = value;
            SkillSelectedEvent?.Invoke(selectedSkill);
        }
    }

    /// <summary>
    /// 显示技能信息，需要先确保已调用 <see cref="SelectedSkill"/> 选中技能
    /// </summary>
    public void DisplaySkill()
    {
        Debug.Log("invoke DisplaySkill");
        if (selectedSkill == null)
        {
            Debug.LogWarning($"DisplaySkill() selectedSkill is null");
            return;
        }
        skillImage.sprite = selectedSkill.skillSprite;
        skillNameText.text = selectedSkill.skillName;
        skillLevelText.text = selectedSkill.skillLevel.ToString();
        skillDesText.text = selectedSkill.skillDes;
    }

    /// <summary>
    /// 升级技能，需要先确保已调用 <see cref="SelectedSkill"/> 选中技能
    /// </summary>
    public void UpgradeSkill()
    {
        Debug.Log("invoke UpgradeSkill");
        if (selectedSkill == null)
        {
            Debug.LogWarning("UpgradeSkill() selectedSkill is null");
            return;
        }
        if (!selectedSkill.isUnlocked)
        {
            Debug.LogWarning("UpgradeSkill() selectedSkill is locked");
            return;
        }
        if (!IsEnoughPoints())
        {
            Debug.LogWarning($"UpgradeSkill() skillPoints not enough: {skillPoints}/{maxSkillPoints}");
            return;
        }
        if (selectedSkill.CanUpgrade())
        {
            selectedSkill.skillLevel++;
            skillPoints--;

            DisplaySkill();     // 刷新显示信息
            UpgradeSkillEvent?.Invoke(selectedSkill);
            UpdateSkillStatus();
        }
    }

    /// <summary>
    /// 增加最大技能点数
    /// </summary>
    /// <param name="points">增加的点数</param>
    public void AddMaxSkillPoint(int points)
    {
        maxSkillPoints += points;
    }

    /// <summary>
    /// 增加可用的技能点数
    /// </summary>
    /// <param name="points">增加的点数</param>
    public void AddSkillPoint(int points)
    {
        skillPoints += points;
    }

    /// <summary>
    /// 判断可用技能点数是否足够用于升级
    /// </summary>
    /// <returns>当可用点数不足时返回<c>false</c></returns>
    public bool IsEnoughPoints()
    {
        return skillPoints > 0;
    }
    #endregion


    #region 内部方法
    void UpdateSkillStatus()
    {
        foreach (SkillButton skillBtn in skillButtons)
        {
            if (skillBtn.skillData == null)
            {
                continue;
            }
            if (skillBtn.skillData.CanUnlock())
            {
                skillBtn.UnlockSkill();
            }
        }
    }

    #endregion
}
